package com.credithc.customers.api.aspect;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.credithc.customers.base.codes.CustomerCodes;
import com.credithc.customers.base.configure.PropertiesConfig;
import com.credithc.customers.base.constants.CustomerConstants;
import com.credithc.customers.base.exception.CustomerException;
import com.credithc.customers.base.factory.DictionaryFactory;
import com.credithc.customers.base.mapper.SystemInfoMapper;
import com.credithc.customers.base.po.SystemInfoPo;
import com.credithc.customers.base.service.ICommonService;
import com.credithc.customers.base.utils.ClassUtils;
import com.credithc.customers.base.utils.RSAUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Component;

import java.security.GeneralSecurityException;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author zhukai
 * @date 2018/11/29 9:47
 */
@Component
@Aspect
@Slf4j
public class CheckRequestParam {

    private final PropertiesConfig propertiesConfig;
    private final ICommonService commonService;
    private final SystemInfoMapper systemInfoMapper;

    @Autowired
    public CheckRequestParam(PropertiesConfig propertiesConfig, ICommonService commonService, SystemInfoMapper systemInfoMapper) {
        this.propertiesConfig = propertiesConfig;
        this.commonService = commonService;
        this.systemInfoMapper = systemInfoMapper;
    }

    @Pointcut("execution(public * com.credithc.customers.api.utils.RequestUtils.checkRequestBaseParam(..))")
    public void checkParam() {
    }

    @Before("checkParam()")
    public void checkBaseParamBeforeExecute(JoinPoint jp) {
        Object[] args = jp.getArgs();
        if (args.length > 0) {
            if (args[0] instanceof String) {
                log.info("==============校验参数=============" + (String) args[0]);
                JSONObject jsonObject = JSON.parseObject((String) args[0]);
                LinkedHashMap jsonMap = JSON.parseObject((String) args[0], LinkedHashMap.class, Feature.OrderedField);
                String body = JSON.toJSONString(jsonMap.get("body"));
//                log.info("===========body===========" + body);
                boolean isBatch = false;
//                if (!(jsonMap.get("body") instanceof JSONArray)) {
//                    isBatch = true;
//                }
                Long requestTimestamp = (Long) jsonObject.get("requestTimestamp");
                if (requestTimestamp == null) {
                    throw new CustomerException(CustomerCodes.PARAM_VALIDATE_ERROR, "时间戳不能为空");
                }
                //测试环境不校验时间戳 不设置noCheckTimestamp或设置为false表示校验时间戳，noCheckTimestamp设置为true表示不校验
                if (!propertiesConfig.isNoCheckTimestamp()) {
                    checkTimestamp(requestTimestamp);
                }
                String systemSign = (String) jsonObject.get("systemSign");
                String subSystemSign = (String) jsonObject.get("subSystemSign");
                if (StringUtils.isBlank(systemSign)) {
                    throw new CustomerException(CustomerCodes.PARAM_VALIDATE_ERROR, "系统标识不能为空");
                }
                if (StringUtils.isBlank(subSystemSign)) {
                    throw new CustomerException(CustomerCodes.PARAM_VALIDATE_ERROR, "子系统标识不能为空");
                }
                String signature = (String) jsonObject.get("signature");
                if (!isBatch) {
                    if (StringUtils.isBlank(signature)) {
                        throw new CustomerException(CustomerCodes.PARAM_VALIDATE_ERROR, "签名不能为空");
                    }
                }
                try {
                    SystemInfoPo po = new SystemInfoPo();
                    po.setParentId(systemSign);
                    po.setSystemSign(subSystemSign);
                    po = systemInfoMapper.selectOne(po);
                    if (po == null) {
                        throw new CustomerException(CustomerCodes.PARAM_VALIDATE_ERROR, "系统标识对应的业务系统不存在");
                    }
//                    else {
//                        Integer accessed = po.getAccessed();
//                        if (accessed == null || accessed.equals(CustomerConstants.SYSTEM_NOT_ACCESSED)) {
//                            po.setAccessed(CustomerConstants.SYSTEM_ACCESSED);
//                            po.setAccessTime(new Timestamp(System.currentTimeMillis()));
//                            systemInfoMapper.updateByPrimaryKey(po);
//                        }
//                    }
                    if (!isBatch) {
                        if (propertiesConfig.isNeedVerifySign()) {
                            checkSignature(body, signature, po);
                        }
                        //判断是否需要API验签 对于恒生活统一登录已授权接口才开放校验,在字典表unifyCheckRule添加对应系统和验签场景开启验签
                        Map<String, String> checkRuleDictMap = DictionaryFactory.Dict.UNIFY_CHECK_RULE.getDictMap();
                        String checkRule = checkRuleDictMap.get(subSystemSign);
                        if(StringUtils.isNotBlank(checkRule)&&(CustomerConstants.UNIFY_CHECK_ALL.equalsIgnoreCase(checkRule)||CustomerConstants.UNIFY_CHECK_API.equalsIgnoreCase(checkRule))){
                            checkSignature(body, signature, po);
                        }
                    }
                } catch (DataAccessException e) {
                    log.error("查询系统报错:" + ClassUtils.getClassName() + "--" + ClassUtils.getMethodName() + "--" + e.getMessage());
                    throw new CustomerException(CustomerCodes.DATABASE_ERROR_QUERY);
                }
            }
        }
    }

    private void checkTimestamp(Long requestTimestamp) {
        Long currentTimestamp = System.currentTimeMillis();
        if ((Math.abs(currentTimestamp - requestTimestamp)) > propertiesConfig.getExpiredTime()) {
            throw new CustomerException(CustomerCodes.REQUEST_TIME_OUT);
        }
    }

    private void checkSignature(String data, String signature, SystemInfoPo system) {
        try {
            log.info("本地生成的签名========" + RSAUtils.createSign(data, system.getPrivateKey()));
            log.info("调用方生成的签名=======" + signature);
//            log.info("私钥=======" + system.getPrivateKey());
            boolean v = commonService.verifySign(data, signature, system);
            if (!v) {
                throw new CustomerException(CustomerCodes.SIGN_FAIL);
            }
        } catch (GeneralSecurityException e) {
            log.error("验签异常:" + ClassUtils.getClassName() + "--" + ClassUtils.getMethodName() + "--" + e.getMessage());
            throw new CustomerException(CustomerCodes.SIGN_EXCEPTION);
        }
    }

}
